#ifndef BANK_ACCOUNT_H
#define BANK_ACCOUNT_H

#include <string>
#include <stdexcept>

namespace MiniBanking
{

    /**
     * @brief Abstract base class representing a generic bank account.
     *
     * Defines the common interface and attributes for all account types (Savings, Checking).
     * It enforces implementation of account-type-specific behaviors through pure virtual functions.
     */
    class BankAccount
    {
    protected:
        std::string accountID_;
        std::string ownerName_; // Store owner name for convenience in display/reports
        double balance_;

        /**
         * @brief Decreases the account balance. Internal use.
         * @param amount The positive amount to decrease.
         * @return True if the balance was successfully decreased (sufficient funds), false otherwise.
         */
        bool decreaseBalance(double amount);

        /**
         * @brief Increases the account balance. Internal use.
         * @param amount The positive amount to increase.
         */
        void increaseBalance(double amount);

    public:
        /**
         * @brief Constructs a new BankAccount object.
         * @param accountID The unique ID for the account.
         * @param ownerName The name of the account holder.
         * @param initialBalance The starting balance (defaults to 0.0, must be non-negative).
         * @throws std::invalid_argument if initialBalance is negative.
         */
        BankAccount(std::string accountID, std::string ownerName, double initialBalance = 0.0);

        // Virtual destructor is crucial for base classes with virtual functions
        virtual ~BankAccount() = default;

        // --- Getters ---
        const std::string &getAccountID() const;
        const std::string &getOwnerName() const;
        double getBalance() const;

        // --- Pure Virtual Functions (Must be implemented by derived classes) ---

        /**
         * @brief Gets the specific type of the account (e.g., "Savings Account").
         * @return A string representing the account type.
         */
        virtual std::string getAccountType() const = 0;

        /**
         * @brief Checks if a transfer *from* this account *to* the destination account is permitted by the rules of this account type.
         * Does not check balance, only rules (e.g., Savings can only transfer to owner's Checking).
         * @param destination The account to potentially transfer to.
         * @return True if the transfer is rule-compliant, false otherwise.
         */
        virtual bool canTransferTo(const BankAccount &destination) const = 0;

        // --- Virtual Functions (Can be overridden by derived classes, provide default behavior) ---

        /**
         * @brief Attempts to deposit funds into the account.
         * Default implementation does nothing and returns false (for account types that don't support deposit).
         * @param amount The amount to deposit (must be positive).
         * @return True if deposit was successful, false otherwise.
         */
        virtual bool deposit(double amount);

        /**
         * @brief Attempts to withdraw funds from the account.
         * Default implementation does nothing and returns false (for account types that don't support withdrawal).
         * @param amount The amount to withdraw (must be positive).
         * @return True if withdrawal was successful, false otherwise.
         */
        virtual bool withdraw(double amount);

        /**
         * @brief Attempts to initiate a transfer FROM this account.
         * This base implementation primarily checks for sufficient funds and decreases the balance.
         * Derived classes should override this to first call canTransferTo and then this base logic (or implement fully).
         * The coordination of increasing the destination balance is handled by BankSystem.
         * @param amount The amount to transfer (must be positive).
         * @return True if the balance was sufficient and decreased, false otherwise.
         */
        virtual bool initiateTransferOut(double amount);

        /**
         * @brief Receives funds from a transfer. Called by BankSystem.
         * @param amount The positive amount being transferred in.
         * @return True if successful, false otherwise (e.g., non-positive amount).
         */
        virtual bool receiveTransfer(double amount);

        // Note: Copy/Move constructors/assignments are defaulted. Be careful if adding raw pointers.
        BankAccount(const BankAccount &) = default;
        BankAccount &operator=(const BankAccount &) = default;
        BankAccount(BankAccount &&) = default;
        BankAccount &operator=(BankAccount &&) = default;
    };

}

#endif
